#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SOURCE_IP "192.168.56.128"
#define DESTINATION_IP "192.168.56.1"
unsigned short get_checksum(unsigned short *ptr, int len) {  
    register long sum;  
    unsigned short oddbyte;  
    register short answer;  
    sum = 0;  
    while (len > 1) {  
        sum += *ptr++;  
        len -= 2;  
    }  
    if (len == 1) {  
        oddbyte = 0;  
        *((unsigned char*)&oddbyte) = *(unsigned char*)ptr;  
        sum += oddbyte;  
    }  
    sum = (sum >> 16) + (sum & 0xffff);  
    sum += (sum >> 16);  
    answer = (short)~sum;  
    return answer;  
} 
int main() {
    int sockfd;
    char buffer[4096]= {0};
    char data[5]="hello";
    struct iphdr *iph = (struct iphdr *) buffer;
    struct icmphdr *icmph = (struct icmphdr *) (buffer + sizeof(struct iphdr));
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sockfd < 0) {
        perror("socket");
        exit(1);
    }
    memset(buffer, 0, sizeof(buffer));
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr) + sizeof(data);
    iph->id = htonl(54321);
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_ICMP;
    iph->saddr = inet_addr(SOURCE_IP);
    iph->daddr = inet_addr(DESTINATION_IP);
    iph->check = get_checksum((unsigned short*)buffer,iph->tot_len);    
    icmph->type = ICMP_ECHO;
    icmph->code = 0;
    icmph->un.echo.id = 0;
    icmph->un.echo.sequence = 0;
    memcpy((void*)(buffer + sizeof(struct iphdr) + sizeof(struct icmphdr)), (void*)data, sizeof(data));
    icmph->checksum = get_checksum((unsigned short*)icmph,sizeof(struct icmphdr) + sizeof(data));
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));  
    sin.sin_family = AF_INET;  
    sin.sin_addr.s_addr = inet_addr(DESTINATION_IP);   
    if (sendto(sockfd, buffer, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
        perror("sendto");
        exit(1);
    }
    close(sockfd);
    return 0;
}
